package com.jk1123.igs.api.util;


import com.jk1123.igs.common.util.ByteUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.io.ByteArrayInputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

/**
 * @author huyoufu <https://github.com/huyoufu>
 * @TIME 2021-09-13 18:59
 * @description
 */
@Component
@Slf4j
public class UnOrderIdGeneratorDataSourceHelper {
    @Autowired
    private DataSource dataSource;
    private final String SEGMENT_TABLE_NAME="t_id_rand_seg";
    /**
     * 62的五次方
     */
    private final long begin=916132832L;
    /**
     * 62的6次方 916132832L 到56800235584L 之间保持1万的使用 所以最大值 56800232832L
     */
    //private final long end=56800235584L;
    private final long end=56800232832L;
    //每一段区间为10000
    private final int SECTION_SIZE=10000;
    //每十段组成一条记录 也就是10万
    private final int SECTION_NUM_OF_RECORD=10;

    private final int BATCH_SIZE=10000;

    public boolean initTable(){
        //初始化表结构

        return true;
    }

    public void initDataSource(){

        log.info("开始初始化 id 段~~~");
        int len= (int) ((end-begin)/SECTION_SIZE);
        //初始化数据
        List<Long> list=new ArrayList<>(len);
        for (long i=begin;i<end;i+=SECTION_SIZE){
            list.add(i);
        }
        //随机化数据
        Collections.shuffle(list);

        List<Long[]> records=new ArrayList<>(len/SECTION_NUM_OF_RECORD);

        Long[] record=new Long[SECTION_NUM_OF_RECORD];

        for (int i=0,j=1;i<list.size();i++,j++){

            record[(j-1)%SECTION_NUM_OF_RECORD]=list.get(i);
            //每次取出十个数字
            if (j%SECTION_NUM_OF_RECORD==0){
                //insertDatasource(sections);
                Long[] newRecord=new Long[SECTION_NUM_OF_RECORD];
                System.arraycopy(record,0,newRecord,0,SECTION_NUM_OF_RECORD);
                records.add(newRecord);
            }
        }
        log.info("初始化完毕 id 段~~~");
        insertDatasource(records);
    }

    public void insertDatasource(List<Long[]>  records){
        log.info("开始批量插入 id 段数据到数据库中~~~");
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            PreparedStatement ps = connection.prepareStatement("insert into "+SEGMENT_TABLE_NAME+" values (null,?,1)");
            for (int i=0;i<records.size();i++) {
                if (i!=0&&i%BATCH_SIZE==0){
                    log.info("正在插入到数据库中记录,当前是第{}次,当前i是{}",i/BATCH_SIZE,i);
                    ps.executeBatch();
                    ps.clearBatch();
                }
                Long[] record=records.get(i);
                ps.setBlob(1,new ByteArrayInputStream(ByteUtil.longArray2Bytes(record)));
                ps.addBatch();
            }
            ps.clearBatch();
            //剩下最后的部分
            for (int i=records.size()%BATCH_SIZE, j=records.size();i>0;i--,j--){
                Long[] record = records.get(j - 1);
                ps.setBlob(1,new ByteArrayInputStream(ByteUtil.longArray2Bytes(record)));
                ps.addBatch();
            }
            ps.executeBatch();
            ps.close();
            connection.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        log.info("批量插入 id 段数据到数据库中结束~~~");
    }
    public long[] getSections(){

        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            PreparedStatement ps = connection.prepareStatement("select sections from "+SEGMENT_TABLE_NAME+" where used!=1 limit 1");
            ResultSet resultSet = ps.executeQuery();
            byte[] bytes =null;
            while (resultSet.next()){
                bytes=resultSet.getBytes(1);

            }
            ps.close();
            connection.close();
            long[] longArray = ByteUtil.bytes2LongArray(bytes);

            return longArray;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

    }
}
